<?php
require_once('../engine/engine.php');
require_once('../dbo/records.php');
/**#@-*/

init_page(LOAD_TAB);

// check that requested record exists

$id     = ustr2int(try_request('id'));
$record = record_find($id);

$project_id = $record['project_id'];

// retrieve state_abbr for current records state_id
// we'll need it later when drawing circle for root node 
$state = state_find($record["state_id"]);
$record["state_abbr"] = $state["state_abbr"];

if (!$record)
{
    debug_write_log(DEBUG_NOTICE, 'Record cannot be found.');
    exit;
}

$levels = array(array($id));
$connections = array();
$nodes = array($id=>$record);

$uplevels = array();

// retrieve subrecords (childs) = nodes we depend on
retrieve_dependencies($id, $levels, $connections, $nodes, $project_id);

// retrieve parents = nodes that depend on us
retrieve_dependencies($id, $uplevels, $connections, $nodes, $project_id, "parents_list");

$res = merge_levels($levels,$uplevels);
$unified_levels = $res["unified"];
$width = $res["max_width"];

//print "Levels: ".print_r($unified_levels,true)."<br/><br/>";
//print "Connections: ".print_r($connections,true)."<br/>";

dependency_graph($unified_levels,$connections,$width, $nodes, $id);

function dependency_graph($levels, $connections, $width, $nodes, $root_id)
{
	global $handle, $diameter, $green_circle, $orange_circle, $line_color, $txt_color, $root_txt_color;

	/* circle (node) diameter */
	$diameter = 40;
	/* height (0y) difference between varios layers */
	$diff_layers = 65;
	/* width (0x) difference between nodes in the same layer */
	$diff_nodes = 60;
	/* image border */
	$border = 20;

	$count_levels = count($levels);

	$image_height = $border*2 + $count_levels*$diff_layers;
	$image_width = $border*2 + $width*$diameter + ($width-1)*$diff_nodes;

//	header ("Content-type: image/png");
	$handle = ImageCreate($image_width, $image_height) or die ("Cannot Create image");
	$bg_color = ImageColorAllocate ($handle, 251, 251, 251);
	$txt_color = ImageColorAllocate ($handle, 12, 12, 12);
	$root_txt_color = ImageColorAllocate ($handle, 100, 100, 255);
	$green_circle = ImageColorAllocate ($handle, 82,185,11);
	$orange_circle = ImageColorAllocate ($handle, 250,100,2);
	$line_color = ImageColorAllocate ($handle, 100, 100, 100);

	for ($i=0; $i<$count_levels; $i++) {
		$level_width = count($levels[$i]);
		if ($width==$level_width) {
			$x = $border + floor($diameter/2);
			$diff = $diff_nodes;
		} else {
			$diff = ($image_width-$border*2-$level_width*$diameter)/($level_width+1);
			$x = $border + $diff + floor($diameter/2);
		}

		$y = $border + $i*$diff_layers + floor($diameter/2);

		for ($j=0; $j<$level_width; $j++) {
			$id = $levels[$i][$j];
			if ($j>0)
				$x = $x + $diff + $diameter;
			draw_node($x,$y,$id,$nodes,$root_id);
			$nodes[$id]["x"] = $x;
			$nodes[$id]["y"] = $y;
			$drown_nodes[] = $id;
		}
	} 

	$count_conn = count($connections);
	for ($i=0; $i<$count_conn; $i++)
		draw_line($nodes,$connections[$i]);

	$name = "depgraph".time().rand(0,99);
	ImagePng ($handle, "../generated/$name.png");
	imagedestroy($handle);

	print "<img src='../generated/$name.png' usemap='#bugmap'/>";
	print "<map name='bugmap'>";

	$radius = $diameter/2;
	$cnt_nodes = count($nodes);
	foreach ($nodes as $id=>$node)
		print "<area shape='circle' coords='".$node["x"].",".$node["y"].",$radius' href='view.php?id=$id' title='Subject: ".$node["subject"]."&#10;State: ".$node["state_abbr"]."' >";
	print "</map>";	
}

function draw_node($x, $y, $id, $nodes, $root_id)
{
	global $handle, $diameter, $green_circle, $orange_circle, $txt_color, $root_txt_color;

	$state_abbr = $nodes[$id]["state_abbr"];

	if ($state_abbr!="N" && $state_abbr!="A") {
		$color = "green";	
	} else {
		$color = "orange";
	}

	ImageFilledEllipse($handle, $x, $y, $diameter, $diameter, ${$color."_circle"});
	$font_x = $x-$diameter/4;
	$font_y = $y-$diameter/4;

	$color = ($root_id==$id) ? $root_txt_color : $txt_color;
	ImageString ($handle, 18, $font_x, $font_y, $id, $color);
	if ($root_id==$id)
		ImageEllipse($handle, $x, $y, $diameter+6, $diameter+6, $root_txt_color);
}

function draw_line($nodes, $pair)
{
	global $diameter, $line_color, $handle;

	$x1 = $nodes[$pair[0]]["x"];
	$x2 = $nodes[$pair[1]]["x"];

	$y1 = $nodes[$pair[0]]["y"]-$diameter/2;
	$y2 = $nodes[$pair[1]]["y"]+$diameter/2;

	ImageLine($handle, $x1, $y1, $x2, $y2, $line_color);
	ImageFilledEllipse($handle, $x1, $y1, 7, 7, $line_color);
}

function retrieve_dependencies($id, &$levels, &$connections, &$nodes, $project_id, $func="subrecords_list", $level_index=0)
{
	$level_index++;
	$list = $func($id);

	if ($list->rows && !isset($levels[$level_index]))
		$levels[$level_index] = array();

	// for testing purposes return know error
	while (($row = $list->fetch())) {
		// if record is not in current project make sure user has right to see it
		if ($row['project_id']!=$project_id) {
			$rec = record_find($row['record_id']);
			if (!$rec) {
				// this should not happen
				continue;
			}
			$permissions = record_get_permissions($rec['template_id'], $rec['creator_id'], $rec['responsible_id']);
			if (!can_record_be_displayed($permissions)) {
				// don't display this record for this user
				continue;
			}
		}

		if (!in_array($row['record_id'],$levels[$level_index]))
			$levels[$level_index][] = $row['record_id'];

		// the order of the elements is important for the arrow that will be drawn
		// first is parent node, then child node
		if ($func=="subrecords_list")
			$connections[] = array($id,$row['record_id']);
		else
			$connections[] = array($row['record_id'],$id);

		if (!isset($nodes[$row['record_id']]))
			$nodes[$row['record_id']] = $row;

		retrieve_dependencies($row['record_id'],$levels,$connections,$nodes,$project_id,$func,$level_index);
	}
}

function merge_levels($levels,$uplevels)
{
	$unified = array();
	$max_width = 0;

	$drown_nodes = array();

	$cnt = count($levels);
	for ($i=$cnt-1; $i>=0; $i--) {
		$unified[] = array();
		$index = count($unified)-1;
		for ($j=0; $j<count($levels[$i]); $j++)
			if (!in_array($levels[$i][$j], $drown_nodes)) {
				// if we have dependency on a node that was displayed on a previous level, don't add it to this level
				// the connection will be done to the node drown on the previous level
				$unified[$index][] = $levels[$i][$j];
				$drown_nodes[] = $levels[$i][$j];
			}
		if (count($unified[$index])>$max_width)
			$max_width = count($unified[$index]);
	}

	$cnt = count($uplevels);

	// uplevels has indexes between 1 - $cnt (includig $cnt)
	for ($i=1; $i<=$cnt; $i++) {
		$unified[] = array();
		$index = count($unified)-1;
		for ($j=0; $j<count($uplevels[$i]); $j++)
			if (!in_array($uplevels[$i][$j], $drown_nodes)) {
				$unified[$index][] = $uplevels[$i][$j];
				$drown_nodes[] = $uplevels[$i][$j];
			}
		if (count($unified[$index])>$max_width)
			$max_width = count($unified[$index]);
	}

	return array("unified"=>$unified, "max_width"=>$max_width);
}

?>
